//SPDX-FileCopyrightText: Copyright 2025-2025 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package board_dao

import (
	"context"

	"gitcode.com/eteam/api-server/dao/common"
	"gitcode.com/eteam/proto-gen-go.git/board_draw_api"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

type BasicDrawInfoDbItem struct {
	DrawName string `bson:"drawName"`
}

type DrawInfoDbItem struct {
	DrawId               string              `bson:"_id"`
	BoardId              string              `bson:"boardId"`
	BasicInfo            BasicDrawInfoDbItem `bson:"basicInfo"`
	EditMemberUserIdList []string            `bson:"editMemberUserIdList"`
	NodeCount            uint32              `bson:"nodeCount"`
	EdgeCount            uint32              `bson:"edgeCount"`
	CreateTime           int64               `bson:"createTime"`
	UpdateTime           int64               `bson:"updateTime"`
	LastChatTime         int64               `bson:"lastChatTime"`
}

func (item *DrawInfoDbItem) ToDrawInfo() *board_draw_api.DrawInfo {
	editMemberUserIdList := item.EditMemberUserIdList
	if editMemberUserIdList == nil {
		editMemberUserIdList = []string{}
	}
	return &board_draw_api.DrawInfo{
		DrawId:  item.DrawId,
		BoardId: item.BoardId,
		BasicInfo: &board_draw_api.BasicDrawInfo{
			DrawName: item.BasicInfo.DrawName,
		},
		EditMemberUserIdList: editMemberUserIdList,
		NodeCount:            item.NodeCount,
		EdgeCount:            item.EdgeCount,
		CreateTime:           item.CreateTime,
		UpdateTime:           item.UpdateTime,
		LastChatTime:         item.LastChatTime,
	}
}

func (item *DrawInfoDbItem) CanEdit(memberUserId string) bool {
	for _, editeUserId := range item.EditMemberUserIdList {
		if editeUserId == memberUserId {
			return true
		}
	}
	return false
}

type _DrawInfoDao struct {
	mc *mongo.Collection
}

func newDrawInfoDao(db *mongo.Database) (*_DrawInfoDao, error) {
	mc := db.Collection(common.DB_NS_BOARD + "draw")
	_, err := mc.Indexes().CreateMany(context.Background(), []mongo.IndexModel{
		{
			Keys: bson.D{{"boardId", 1}, {"createTime", 1}},
		},
		{
			Keys: bson.D{{"boardId", 1}, {"lastChatTime", 1}},
		},
	})
	if err != nil {
		return nil, err
	}
	return &_DrawInfoDao{mc: mc}, nil
}

func (db *_DrawInfoDao) Insert(ctx context.Context, dbItem *DrawInfoDbItem) error {
	_, err := db.mc.InsertOne(ctx, dbItem)
	return err
}

func (db *_DrawInfoDao) Exist(ctx context.Context, boardId, drawId string) (bool, error) {
	count, err := db.mc.CountDocuments(ctx, bson.M{"_id": drawId, "boardId": boardId})
	return count > 0, err
}

func (db *_DrawInfoDao) Get(ctx context.Context, boardId, drawId string) (*DrawInfoDbItem, error) {
	retItem := &DrawInfoDbItem{}
	err := db.mc.FindOne(ctx, bson.M{"_id": drawId, "boardId": boardId}).Decode(retItem)
	return retItem, err
}

func (db *_DrawInfoDao) Remove(ctx context.Context, boardId, drawId string) error {
	_, err := db.mc.DeleteOne(ctx, bson.M{"_id": drawId, "boardId": boardId})
	return err
}

func (db *_DrawInfoDao) CountByBoard(ctx context.Context, boardId string) (uint32, error) {
	count, err := db.mc.CountDocuments(ctx, bson.M{"boardId": boardId})
	return uint32(count), err
}

func (db *_DrawInfoDao) ListByBoard(ctx context.Context, boardId string, orderBy board_draw_api.DRAW_ORDER_BY, offset, limit int64) ([]*DrawInfoDbItem, error) {
	sortParam := bson.M{"createTime": -1}
	if orderBy == board_draw_api.DRAW_ORDER_BY_DRAW_ORDER_BY_CHAT {
		sortParam = bson.M{"lastChatTime": -1}
	}
	cursor, err := db.mc.Find(ctx, bson.M{"boardId": boardId},
		options.Find().SetSkip(offset).SetLimit(limit).SetSort(sortParam))
	if err != nil {
		return nil, err
	}
	retList := []*DrawInfoDbItem{}
	err = cursor.All(ctx, &retList)
	return retList, err
}

func (db *_DrawInfoDao) ListById(ctx context.Context, drawIdList []string, filterByBoard bool, boardIdList []string) ([]*DrawInfoDbItem, error) {
	if len(drawIdList) == 0 {
		return []*DrawInfoDbItem{}, nil
	}
	query := bson.M{"_id": bson.M{"$in": drawIdList}}
	if filterByBoard {
		if len(boardIdList) == 0 {
			return []*DrawInfoDbItem{}, nil
		}
		query["boardId"] = bson.M{"$in": boardIdList}
	}
	cursor, err := db.mc.Find(ctx, query)
	if err != nil {
		return nil, err
	}
	retList := []*DrawInfoDbItem{}
	err = cursor.All(ctx, &retList)
	return retList, err
}

func (db *_DrawInfoDao) UpdateBasic(ctx context.Context, boardId, drawId string, basicItem *BasicDrawInfoDbItem, updateTime int64) error {
	_, err := db.mc.UpdateOne(ctx, bson.M{"_id": drawId, "boardId": boardId}, bson.M{"$set": bson.M{
		"basicInfo":  basicItem,
		"updateTime": updateTime,
	}})
	return err
}

func (db *_DrawInfoDao) UpdateNodeCount(ctx context.Context, boardId, drawId string, count uint32, updateTime int64) error {
	_, err := db.mc.UpdateOne(ctx, bson.M{"_id": drawId, "boardId": boardId}, bson.M{"$set": bson.M{
		"nodeCount":  count,
		"updateTime": updateTime,
	}})
	return err
}

func (db *_DrawInfoDao) UpdateEdgeCount(ctx context.Context, boardId, drawId string, count uint32, updateTime int64) error {
	_, err := db.mc.UpdateOne(ctx, bson.M{"_id": drawId, "boardId": boardId}, bson.M{"$set": bson.M{
		"edgeCount":  count,
		"updateTime": updateTime,
	}})
	return err
}

func (db *_DrawInfoDao) UpdateEditMemberUserIdList(ctx context.Context, boardId, drawId string, editMemberUserIdList []string, updateTime int64) error {
	_, err := db.mc.UpdateOne(ctx, bson.M{"_id": drawId, "boardId": boardId}, bson.M{"$set": bson.M{
		"editMemberUserIdList": editMemberUserIdList,
		"updateTime":           updateTime,
	}})
	return err
}

func (db *_DrawInfoDao) SetUpdateTime(ctx context.Context, boardId, drawId string, updateTime int64) error {
	_, err := db.mc.UpdateOne(ctx, bson.M{"_id": drawId, "boardId": boardId}, bson.M{"$set": bson.M{
		"updateTime": updateTime,
	}})
	return err
}

func (db *_DrawInfoDao) SetLastChatTime(ctx context.Context, boardId, drawId string, lastChatTime int64) error {
	_, err := db.mc.UpdateOne(ctx, bson.M{"_id": drawId, "boardId": boardId}, bson.M{"$set": bson.M{
		"lastChatTime": lastChatTime,
	}})
	return err
}
